﻿namespace MicroCloud.Api.Identity.Areas.Admin.Controllers.Identity
{
    /// <summary>
    /// 角色管理
    /// </summary>
    [Description("角色管理")]
    [ModuleInfo(Code = "Role", Name = "角色管理", OrderNo = 2, Position = "Identity", PositionName = "认证模块")]
    public class RoleController : AdminControllerBase
    {
        #region 属性
        /// <summary>
        /// 获取 身份认证业务契约
        /// </summary>
        protected IIdentityContract IdentityContract => ServiceProvider.GetService<IIdentityContract>();
        
        /// <summary>
        /// 获取 角色管理器
        /// </summary>
        protected RoleManager<Role> RoleManager => ServiceProvider.GetService<RoleManager<Role>>();

        #endregion

        #region Action方法
        /// <summary>
        /// 读取角色
        /// </summary>
        /// <param name="request">分页请求</param>
        /// <returns>角色页列表</returns>
        [HttpPost]
        [ModuleInfo]
        [Description("读取")]
        public virtual PageData<RoleOutputDto> Read(PageRequest request)
        {
            Check.NotNull(request, nameof(request));
            IFunction function = this.GetExecuteFunction();

            Func<Role, bool> updateFunc = FilterService.GetDataFilterExpression<Role>(null, DataAuthOperation.Update).Compile();
            Func<Role, bool> deleteFunc = FilterService.GetDataFilterExpression<Role>(null, DataAuthOperation.Delete).Compile();
            Expression<Func<Role, bool>> predicate = FilterService.GetExpression<Role>(request.FilterGroup);

            PageResult<RoleOutputDto> page;
            using (var scope = ServiceProvider.CreateScope())
            {
                var userRepository = scope.ServiceProvider.GetService<IRepository<User, long>>();

                page = CacheService.ToPageCache(RoleManager.Roles, predicate, request.PageCondition, m => new
                {
                    R = m,
                    Creator = GetUser(userRepository, m.CreatorId),
                    Updater = GetUser(userRepository, m.UpdaterId),
                }, function).ToPageResult(data => data.Select(m => new RoleOutputDto(m.R)
                {
                    CreatorName = m.Creator.UserName,
                    CreatorNickname = m.Creator.NickName,
                    UpdaterName = m.Updater.UserName,
                    UpdaterNickname = m.Updater.NickName,
                    Updatable = updateFunc(m.R),
                    Deletable = deleteFunc(m.R)
                }).ToArray());

                //page = RoleManager.Roles.ToPage(predicate, request.PageCondition, m => new
                //{
                //    R = m,
                //    Creator = GetUser(userRepository, m.CreatorId),
                //    Updater = GetUser(userRepository, m.UpdaterId),
                //}).ToPageResult(data => data.Select(m => new RoleOutputDto(m.R)
                //{
                //    CreatorName = m.Creator.UserName,
                //    CreatorNickname = m.Creator.NickName,
                //    UpdaterName = m.Updater.UserName,
                //    UpdaterNickname = m.Updater.NickName,
                //    Updatable = updateFunc(m.R),
                //    Deletable = deleteFunc(m.R)
                //}).ToArray());

            }

            return page.ToPageData();
        }

        /// <summary>
        /// 读取角色节点
        /// </summary>
        /// <returns>角色节点列表</returns>
        [HttpGet]
        [ModuleInfo]
        [Description("读取节点")]
        public virtual RoleNode[] ReadNode()
        {
            IFunction function = this.GetExecuteFunction();
            Expression<Func<Role, bool>> exp = m => !m.IsLocked;

            RoleNode[] nodes = CacheService.ToCacheArray<Role, RoleNode>(RoleManager.Roles, exp, function);
            //RoleNode[] nodes = CacheService.ToCacheArray(RoleManager.Roles, exp, m => new RoleNode()
            //{
            //    RoleId = m.Id,
            //    RoleName = m.Name
            //}, function);
            return nodes;
        }
   
        /// <summary>
        /// 获取角色树
        /// </summary>
        /// <param name="roleIds">已选择的角色编号</param>
        /// <returns>角色树数据</returns>
        [HttpPost]
        [ModuleInfo]
        [Description("获取树")]
        public virtual List<RoleNode> GetRoleNodes(params long[] roleIds)
        {
            Check.NotNull(roleIds, nameof(roleIds));

            IFunction function = this.GetExecuteFunction();
            long[] checkRoleIds = roleIds;

            Expression<Func<Role, bool>> exp2 = m => true;
            List<RoleNode> nodes = CacheService.ToCacheList<Role, RoleNode>(IdentityContract.Roles, exp2, function);

            nodes.ForEach(m => m.IsChecked = checkRoleIds.Contains(m.Id));
            return nodes;
        }

        /// <summary>
        /// 读取角色[用户]树
        /// </summary>
        /// <param name="userId">用户编号</param>
        /// <returns>角色[用户]树数据</returns>
        [HttpGet]
        [ModuleInfo]
        [Description("读取[用户]树")]
        public virtual List<RoleNode> ReadUserRoles(long userId)
        {
            Check.GreaterThan(userId, nameof(userId), 0);

            IFunction function = this.GetExecuteFunction();

            Expression<Func<UserRole, bool>> exp = m => m.UserId.Equals(userId);
            long[] checkRoleIds = CacheService.ToCacheArray(IdentityContract.UserRoles, exp, m => m.RoleId, function);

            Expression<Func<Role, bool>> exp2 = m => !m.IsLocked;
            List<RoleNode> nodes = CacheService.ToCacheList<Role, RoleNode>(IdentityContract.Roles, exp2, function);
            //List<UserRoleNode> nodes = IdentityContract.Roles.Where(m => !m.IsLocked) 
            //    .OrderByDescending(m => m.IsAdmin).ThenBy(m => m.Id).ToOutput<Role, UserRoleNode>().ToList();

            nodes.ForEach(m => m.IsChecked = checkRoleIds.Contains(m.Id));
            return nodes;
        }

        /// <summary>
        /// 读取角色[组织机构]树
        /// </summary>
        /// <param name="organizationId">组织机构编号</param>
        /// <returns>角色[组织机构]树数据</returns>
        [HttpGet]
        [ModuleInfo]
        [Description("读取[组织机构]树")]
        public virtual List<RoleOrganizationNode> ReadOrganizationRoles(long organizationId)
        {
            Check.GreaterThan(organizationId, nameof(organizationId), 0);

            IFunction function = this.GetExecuteFunction();

            Expression<Func<RoleOrganization, bool>> exp = m => m.OrganizationId.Equals(organizationId);
            var roleOrganizations = CacheService.ToCacheList(IdentityContract.RoleOrganizations, exp, m => new { m.RoleId, m.OrganizationId, m.Administrator, m.Leader }, function);

            Expression<Func<Role, bool>> exp2 = m => !m.IsLocked;
            List<RoleOrganizationNode> nodes = CacheService.ToCacheList(IdentityContract.Roles, exp2, m => new RoleOrganizationNode()
            {
                Id = m.Id,
                Name = m.Name,
                Description = m.Description,
                Remark = m.Remark,
                IsAdmin = m.IsAdmin,
                IsSystem = m.IsSystem,
                IsLocked = m.IsLocked,
                //IsChecked = roleOrganizations.Exists(o => Equals(o.RoleId, m.Id)),
                //Administrator = roleOrganizations.Exists(o => Equals(o.RoleId, m.Id)) ? roleOrganizations.FirstOrDefault(o => Equals(o.RoleId, m.Id)).Administrator : false,
                //Leader = roleOrganizations.Exists(o => Equals(o.RoleId, m.Id)) ? roleOrganizations.FirstOrDefault(o => Equals(o.RoleId, m.Id)).Leader : false,
            }, function);
            nodes.ForEach(m =>
            {
                m.IsChecked = roleOrganizations.Exists(o => Equals(o.RoleId, m.Id));
                m.Administrator = roleOrganizations.FirstOrDefault(o => Equals(o.RoleId, m.Id))?.Administrator == true;
                m.Leader = roleOrganizations.FirstOrDefault(o => Equals(o.RoleId, m.Id))?.Leader == true;
            });

            return nodes;
        }

        /// <summary>
        /// 新增角色
        /// </summary>
        /// <param name="dtos">新增角色信息</param>
        /// <returns>JSON操作结果</returns>
        [HttpPost]
        [ModuleInfo]
        [DependOnFunction(nameof(Read))]
        [DependOnFunction(nameof(ReadNode))]
        [DependOnFunction(nameof(GetRoleNodes))]
        [UnitOfWork]
        [Description("新增")]
        public virtual async Task<AjaxResult> Create(params RoleInputDto[] dtos)
        {
            Check.NotNull(dtos, nameof(dtos));
            List<string> names = new();
            foreach (RoleInputDto dto in dtos)
            {
                Role role = dto.MapTo<RoleInputDto, Role>();
                IdentityResult result = await RoleManager.CreateAsync(role);
                if (!result.Succeeded)
                {
                    return result.ToOperationResult().ToAjaxResult();
                }
                names.Add(role.Name);
                dto.Id = role.Id;
            }
            return AjaxResult.Success(dtos, I18N.T("角色 {0} 创建成功", names.ExpandAndToString()));
        }
        
        /// <summary>
        /// 更新角色
        /// </summary>
        /// <param name="dtos">更新角色信息</param>
        /// <returns>JSON操作结果</returns>
        [HttpPost]
        [ModuleInfo]
        [DependOnFunction(nameof(Read))]
        [DependOnFunction(nameof(ReadNode))]
        [DependOnFunction(nameof(GetRoleNodes))]
        [UnitOfWork]
        [Description("更新")]
        public virtual async Task<AjaxResult> Update(params RoleInputDto[] dtos)
        {
            Check.NotNull(dtos, nameof(dtos));
            List<string> names = new();
            foreach (RoleInputDto dto in dtos)
            {
                Role role = await RoleManager.FindByIdAsync(dto.Id.ToString());
                role = dto.MapTo(role);
                IdentityResult result = await RoleManager.UpdateAsync(role);
                if (!result.Succeeded)
                {
                    return result.ToOperationResult().ToAjaxResult();
                }
                names.Add(role.Name);
            }
            return AjaxResult.Success(I18N.T("角色 {0} 更新成功", names.ExpandAndToString()));
        }

        /// <summary>
        /// 删除角色
        /// </summary>
        /// <param name="ids">要删除的角色编号</param>
        /// <returns>JSON操作结果</returns>
        [HttpPost]
        [ModuleInfo]
        [DependOnFunction(nameof(Read))]
        [DependOnFunction(nameof(ReadNode))]
        [DependOnFunction(nameof(GetRoleNodes))]
        [UnitOfWork]
        [Description("删除")]
        public virtual async Task<AjaxResult> Delete(params long[] ids)
        {
            Check.NotNull(ids, nameof(ids));
            List<string> names = new();
            foreach (long id in ids)
            {
                Role role = await RoleManager.FindByIdAsync(id.ToString());
                IdentityResult result = await RoleManager.DeleteAsync(role);
                if (!result.Succeeded)
                {
                    return result.ToOperationResult().ToAjaxResult();
                }
                names.Add(role.Name);
            }
            return AjaxResult.Success(I18N.T("角色 {0} 删除成功", names.ExpandAndToString()));
        }

        /// <summary>
        /// 设置角色用户
        /// </summary>
        /// <param name="dto">角色用户信息</param>
        /// <returns>JSON操作结果</returns>
        [HttpPost]
        [ModuleInfo]
        [DependOnFunction(nameof(Read))]
        [DependOnFunction(nameof(ReadNode))]
        [DependOnFunction(nameof(GetRoleNodes))]
        [DependOnFunction(nameof(ReadUserRoles))]
        [UnitOfWork]
        [Description("设置用户")]
        public virtual async Task<AjaxResult> SetUsers(RoleSetUserDto dto)
        {
            Check.NotNull(dto, nameof(dto));

            OperationResult result = await IdentityContract.SetRoleUsers(dto.RoleId, dto.UserIds);
            return result.ToAjaxResult();
        }

        /// <summary>
        /// 设置角色组织机构
        /// </summary>
        /// <param name="dto">角色组织机构设置DTO</param>
        /// <returns>JSON操作结果</returns>
        [HttpPost]
        [ModuleInfo]
        [DependOnFunction(nameof(Read))]
        [DependOnFunction(nameof(ReadNode))]
        [DependOnFunction(nameof(GetRoleNodes))]
        [DependOnFunction(nameof(ReadOrganizationRoles))]
        [UnitOfWork]
        [Description("设置组织机构")]
        public virtual async Task<AjaxResult> SetOrganizations(RoleSetOrganizationDto dto)
        {
            Check.NotNull(dto, nameof(dto));

            OperationResult result = await IdentityContract.SetRoleOrganizations(dto.RoleId, dto.RoleOrganizations);
            return result.ToAjaxResult();
        }

        #endregion

        #region 私有方法
        /// <summary>
        /// 获取用户信息
        /// </summary>
        /// <param name="userRepository">用户仓储模型</param>
        /// <param name="userId">用户编号</param>
        /// <returns></returns>
        [NonAction]
        [NonFunction]
        protected static UserSimpleDto GetUser(IRepository<User, long> userRepository, long? userId)
        {
            if (userId == null)
            {
                return new UserSimpleDto();
            }

            var user = userRepository.QueryAsNoTracking(o => o.Id == userId).ToCacheFirst<User, UserSimpleDto>(10, false, nameof(UserSimpleDto));
            return user ?? new UserSimpleDto();
        }

        #endregion

    }
}
